/*
 * Filename: g:\espidf_workspace\idf_S3_T-Watch\main\audio\audio_player.cc
 * Path: g:\espidf_workspace\idf_S3_T-Watch\main\audio
 * Created Date: Monday, June 23rd 2025, 11:18:34 am
 * Author: sss
 *
 * Copyright (c) 2025 Your Company
 */

#include "audio_player.h"
#include "esp_log.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/ringbuf.h"
#include "driver/i2s.h"
#include "driver/i2s_types.h"
#include "driver/i2s_std.h"
#include "utils.h"

#include "audio_element.h"
#include "audio_pipeline.h"
#include "audio_event_iface.h"
#include "audio_common.h"
#include "http_stream.h"
#include "i2s_stream.h"
#include "mp3_decoder.h"
#include "pcm_decoder.h"
#include "tts_stream.h"

#include "esp_peripherals.h"

#include <string.h>
#include <ctype.h>

static const char *TAG = "AUDIO_PLAYER";



static audio_pipeline_handle_t pipeline;
static audio_element_handle_t http_stream_reader, i2s_stream_writer, _decoder;
static esp_periph_set_handle_t set;

static void init_player(const char *audio_type)
{
    int rate = 0;
    if (strcmp(audio_type, "pcm") == 0 || strcmp(audio_type, "tts") == 0)
    {
        rate = 16000;
    }else{
        rate = 44100;
    }
    ESP_LOGI(TAG, "Init player with decode type: %s, rate: %d", audio_type, rate);

    // ESP_LOGI(TAG, "[1.0] Init Peripheral Set");
    // esp_periph_config_t periph_cfg = DEFAULT_ESP_PERIPH_SET_CONFIG();
    // periph_cfg.task_core = 1;//在第二个核心上运行
    // set = esp_periph_set_init(&periph_cfg);

    ESP_LOGI(TAG, "[2.0] Create audio pipeline for playback");
    audio_pipeline_cfg_t pipeline_cfg = DEFAULT_AUDIO_PIPELINE_CONFIG();
    pipeline = audio_pipeline_init(&pipeline_cfg);
    mem_assert(pipeline);

    ESP_LOGI(TAG, "[2.1] Create http stream to read data");
    http_stream_cfg_t http_cfg = HTTP_STREAM_CFG_DEFAULT();
    http_stream_reader = http_stream_init(&http_cfg);
    ESP_LOGI(TAG, "[2.4] Register all elements to audio pipeline");
    audio_pipeline_register(pipeline, http_stream_reader, "http");

    ESP_LOGI(TAG, "[2.2] Create i2s stream to write data to codec chip");
    i2s_stream_cfg_t i2s_cfg = I2S_STREAM_CFG_DEFAULT();
    i2s_cfg.type = AUDIO_STREAM_WRITER;
    i2s_stream_writer = i2s_stream_init(&i2s_cfg);
    i2s_stream_set_clk(i2s_stream_writer, rate, 16, 1);
    audio_pipeline_register(pipeline, i2s_stream_writer, "i2s");

    ESP_LOGI(TAG, "[2.5] Link it together http_stream-->_decoder-->i2s_stream-->[codec_chip]");
    if (strcmp(audio_type, "mp3") == 0)
    {
        const char *link_tag[3] = {"http", "mp3", "i2s"};
        ESP_LOGI(TAG, "[2.3] Create mp3 decoder to decode mp3 file");
        mp3_decoder_cfg_t mp3_cfg = DEFAULT_MP3_DECODER_CONFIG();
        _decoder = mp3_decoder_init(&mp3_cfg);
        audio_pipeline_register(pipeline, _decoder, "mp3");
        audio_pipeline_link(pipeline, &link_tag[0], 3);
    }
    else if (strcmp(audio_type, "pcm") == 0)
    {
        const char *link_tag[3] = {"http", "pcm", "i2s"};
        ESP_LOGI(TAG, "[2.3] Create mp3 decoder to decode pcm file");
        pcm_decoder_cfg_t pcm_cfg = DEFAULT_PCM_DECODER_CONFIG();
        pcm_cfg.rate = rate;
        pcm_cfg.channels = 1;
        _decoder = pcm_decoder_init(&pcm_cfg);
        audio_pipeline_register(pipeline, _decoder, "pcm");
        audio_pipeline_link(pipeline, &link_tag[0], 3);
    }
    else if (strcmp(audio_type, "tts") == 0)
    {
        ESP_LOGI(TAG, "[3.1] Create tts stream to read data from chinese strings");
        tts_stream_cfg_t tts_cfg = TTS_STREAM_CFG_DEFAULT();
        tts_cfg.type = AUDIO_STREAM_READER;
        _decoder = tts_stream_init(&tts_cfg);
        audio_pipeline_register(pipeline, _decoder, "tts");

        const char *link_tag[2] = {"tts", "i2s"};
        audio_pipeline_link(pipeline, &link_tag[0], 2);
    }
    


}

static void deinit_player()
{
    ESP_LOGI(TAG, "[ 6 ] Stop audio_pipeline");
    audio_pipeline_stop(pipeline);
    audio_pipeline_wait_for_stop(pipeline);
    audio_pipeline_terminate(pipeline);

    /* Terminate the pipeline before removing the listener */
    audio_pipeline_unregister(pipeline, http_stream_reader);
    audio_pipeline_unregister(pipeline, i2s_stream_writer);
    audio_pipeline_unregister(pipeline, _decoder);

    audio_pipeline_remove_listener(pipeline);

    // esp_periph_set_stop_all(set);
    /* Release all resources */
    audio_pipeline_deinit(pipeline);
    audio_element_deinit(http_stream_reader);
    audio_element_deinit(i2s_stream_writer);
    audio_element_deinit(_decoder);
    // esp_periph_set_destroy(set);
}

void AUDIO_PLAYER::init(const char *initType)
{
    if (strcmp(decodeType, initType) == 0)
    {
        ESP_LOGI(TAG, "Decode type is the same, no need to init player");
    }
    else
    {
        ESP_LOGI(TAG, "Decode type is different, need to init player");
        deinit();
        init_player(initType);
        strcpy(decodeType, initType);
    }
}
void AUDIO_PLAYER::deinit()
{
    if (strcmp(decodeType, "mp3") == 0 || strcmp(decodeType, "pcm") == 0 || strcmp(decodeType, "tts") == 0)
    {
        ESP_LOGI(TAG, "Deinit player");
        deinit_player();
    }

    strcpy(decodeType, "");
}
void AUDIO_PLAYER::play_url(const char *audio_url)
{
    ESP_LOGI(TAG, "Start to play audio from url: %s", audio_url);
    deinit();
    // 转为小写
    char audio_url_lower[100];
    strcpy(audio_url_lower, audio_url);
    to_lower(audio_url_lower);
    // 判断url是否为mp3
    if (strstr(audio_url_lower, ".mp3"))
    {
        init("mp3");
    }
    else if (strstr(audio_url_lower, ".pcm"))
    {
        init("pcm");
    }
    else
    {
        ESP_LOGE(TAG, "Unsupported audio type");
        return;
    }

    ESP_LOGI(TAG, "[2.6] Set up  uri (http as http_stream, mp3 as mp3 decoder, and default output is i2s) url=%s", audio_url);
    audio_element_set_uri(http_stream_reader, audio_url);

    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");
    audio_pipeline_run(pipeline);
}

void AUDIO_PLAYER::play()
{
    ESP_LOGI(TAG, "[ 5 ] Start audio_pipeline");
    audio_pipeline_run(pipeline);
}

void AUDIO_PLAYER::pause()
{
    ESP_LOGI(TAG, "[ 7 ] Pause audio_pipeline");
    audio_pipeline_pause(pipeline);
}
void AUDIO_PLAYER::resume()
{
    ESP_LOGI(TAG, "[ 8 ] Resume audio_pipeline");
    audio_pipeline_resume(pipeline);
}


void AUDIO_PLAYER::say_chinese(const char *chinese_str)
{
    ESP_LOGI(TAG, "Start to say chinese: %s", chinese_str);
    init("tts");
    tts_stream_set_strings(_decoder, chinese_str);
    audio_pipeline_run(pipeline);
}

AUDIO_PLAYER::AUDIO_PLAYER()
{
}

AUDIO_PLAYER::~AUDIO_PLAYER()
{
}